/* eslint-disable no-shadow */
import React, { useCallback, useState, useRef, useEffect } from 'react';
import { Form } from 'antd';
import type { FormInstance, FormProps } from 'antd/lib/form';
import classnames from 'classnames';
import { List, InputItem } from 'antd-mobile';
import dayjs from 'dayjs';
import moment from 'moment'
import CollapsePanel from '../CollapsePanel';
import Icon from '../Icon';
import type { UploadProps } from '../Upload';
import Upload from '../Upload';
import TextareaItem from '../TextareaItem';
import IndexList from '../IndexListItem';
import DatePicker, { transformDate } from '../DatePicker';
import type { MyRequestOptionsInit } from '../Picker';
import Picker from '../Picker';
import LevelSelectItem from '../LevelSelectItem';
import SearchItem from '../SearchItem';
import { validIdUpload, isEmpty } from './util';
import './index.less';

export interface Props extends Omit<FormProps, 'onValuesChange'> {
  sections: any[];
  onValuesChange?: (value, payload?) => void;
  onClick?: (segments) => void;
  footer?: (data) => JSX.Element;
  hasCheckIcon?: boolean;
  hasCollapsePanel?: boolean;
  disabled?: boolean;
  // api请求地址前缀
  apiPrefix?: string;
  // 图片静态地址前缀
  filePathPrefix?: string;
  requestOptions?: (segments) => MyRequestOptionsInit;
  textFormat?: (segments, data) => string;
  onRespone?: UploadProps['onRespone'];
  beforeRemove?: UploadProps['beforeRemove'];
  dataFormat?: (segments, data) => { label: string; value: number; children?: any[] }[];
  getData?: (segments, payload?) => any;
  renderItem?: (segments, data) => JSX.Element | null;
}

const Index = React.forwardRef<FormInstance, Props>((props) => {
  const {
    onValuesChange,
    onClick,
    form,
    sections,
    footer,
    hasCheckIcon,
    hasCollapsePanel,
    disabled: propsDisabled,
    apiPrefix,
    children,
    requestOptions,
    textFormat,
    onRespone,
    filePathPrefix,
    beforeRemove,
    dataFormat,
    renderItem,
    getData,
    ...otherProps
  } = props;
  const sectionFields = useRef({});
  const [pass, setPass] = useState({});

  /**
   * 检查一个区块的form校验
   */
  const validPass = useCallback(async (fields: string[]) => {
    try {
      await form.validateFields(fields);
      return true;
    } catch (error) {
      return false;
    }
  }, []);

  /**
   * 字段变动的回调
   * @param value
   */
  const handleValuesChange = async (value, payload?) => {
    const keys = Object.keys(value);
    if (keys.length >= 0 && hasCheckIcon) {
      const arr = keys[0].split('-');
      const sectionCode = arr[1];
      const passResult = await validPass(sectionFields.current[sectionCode]);
      if (pass[sectionCode] !== passResult) {
        setPass({
          ...pass,
          [sectionCode]: passResult,
        });
      }
    }

    if (typeof onValuesChange === 'function') {
      onValuesChange(value, payload);
    }
  };

  /**
   * 设置按区块分割字段
   */
  const setSectionFields = useCallback((map: any, formItemName: string) => {
    const arr = formItemName.split('-');
    const sectionCode = arr[1];
    if (!Array.isArray(map[sectionCode])) {
      map[sectionCode] = [];
      map[sectionCode].push(formItemName);
      return;
    }
    if (map[sectionCode].indexOf(formItemName) < 0) {
      map[sectionCode].push(formItemName);
    }
  }, []);

  /**
   * 初始化验证是否全填
   */
  useEffect(() => {
    (async () => {
      const promiseValid = [];
      const keys = [];
      for (const key in sectionFields.current) {
        if (Object.prototype.hasOwnProperty.call(sectionFields.current, key)) {
          const fields = sectionFields.current[key];
          // eslint-disable-next-line no-await-in-loop
          promiseValid.push(await validPass(fields));
          keys.push(key);
        }
      }
      const newPass = { ...pass };
      const passArr = await Promise.all(promiseValid);
      keys.forEach((item, index) => {
        newPass[item] = passArr[index];
      });
      setPass(newPass);
    })();
  }, []);

  /**
   * 文本formatf
   * @param segmentItem
   * @param data
   */
  const handleTextFormat = (segmentItem, data) => {
    if (typeof textFormat === 'function') {
      return textFormat(segmentItem, data);
    }
    return '';
  };
  /**
   * 渲染formItem
   * @param segmentItem
   */
  const renderFormItem = (segmentItem, nextSegmentItem, preSegmentItem) => {
    /**
     * 字段类型
     *  0：文本
     *  1：select
     *  2: 数字文本
     *  3：select
     *  4: radio
     *  5: 图片上传
     *  6: 索引列表 （例如带A-Z索引的通讯录）
     *  7: checkbox
     *  8: 二级级联(例如省市)
     *  9: 三级级联(例如省市区)
     *  10：开始时间 (YYYY-MM-DD)
     *  11：结束时间 (YYYY-MM-DD)
     *  12: tab切换级联选择（例如车辆品牌等文案长度较大，需要多个tab显示）
     *  13: search (搜索类型)
     *  14：时间 (YYYY-MM-DD)
     */

    const {
      type,
      name,
      dictionaryList = [], // 下了字典表
      formItemName,
      isEditor, // 1 可编辑
      verificationLength, // 最大长度
      unit = '', // 单位 ： 元/月/年等
      empty, // 0 必填
      // code,
      defaultValue, // 默认值，
      value, // 用户填充的值
      display, // 隐藏类型，
      sourceUrl, // 一些select下拉是请求回来的数据，sourceUrl是api地址
      // params, // 请求需要带上的字段，['handleBank', 'xxx']
      regex, // 正则
      errorTips = '',
      mode='date',
      format='YYYY-MM-DD',
      displayWay, // 用于区分分期材料上传时材料项的type为0不为5
    } = segmentItem;
    /**
     * none 为没有字段， hidden 为隐藏
     */
    const hasFiled = display !== 'none';
    const hiddenFiled = display === 'hidden';
    // 禁用
    const disabled = propsDisabled || isEditor !== 1;
    // 必填
    const required = empty === 0;

    // form 验证规则
    const rules = [{ required, message: `请填写${segmentItem.name}` }] as any[];

    /**
     * 存在返回的正则，就添加正则规则
     */
    if (regex) {
      try {
        rules.push({
          pattern: new RegExp(regex),
          message:
            errorTips ||
            (type === 2
              ? `${segmentItem.name}格式错误, 请输入数字`
              : `${segmentItem.name}格式错误`),
        });
      } catch (error) {
        console.log(error);
      }
    }

    /**
     * 根据是否需要打勾标记
     * 来划分区域字段
     */
    if (hasCheckIcon) {
      setSectionFields(sectionFields.current, formItemName);
    }

    if (Array.isArray(segmentItem)) {
      return segmentItem.map((item, index) => (
        <div key={item.name}>
          {renderFormItem(item, segmentItem[index + 1], segmentItem[index + -1])}
        </div>
      ));
    }

    // 请求配置
    const newRequestOptions =
      typeof requestOptions === 'function' ? () => requestOptions(segmentItem) : undefined;

    // 数据格式化
    const newDataFormat =
      typeof dataFormat === 'function' ? (data) => dataFormat(segmentItem, data) : undefined;

    /**
     * formItem 通用props
     */
    const baseProps = {
      validateFirst: true,
      name: formItemName,
    };

    // input textarea
    if (type === 0 && !segmentItem.hasOwnProperty('displayWay')) {
      const textareaProps = {
        ...baseProps,
      } as any;
      if (!isEmpty(defaultValue)) {
        // 组件 textarea 的 值必须是 string类型
        textareaProps.initialValue = defaultValue.toString();
      }
      if (!isEmpty(value)) {
        // 组件 textarea 的 值必须是 string类型
        textareaProps.initialValue = value.toString();
      }
      return !hasFiled ? null : (
        <Form.Item
          className={classnames({ 'hr-form-item-hidden': hiddenFiled, [formItemName]: true })}
          name={formItemName}
          rules={rules}
          {...textareaProps}
        >
          <TextareaItem
            labelNumber={7}
            className="hr-textarea"
            disabled={disabled}
            title={
              <div>
                {required && <span className="require-icon">*</span>}
                {name}
              </div>
            }
            placeholder={disabled ? '-' : '请填写'}
            autoHeight
            maxLength={verificationLength || undefined}
            extra={unit}
            onBlur={(value) => handleValuesChange({ [formItemName]: value })}
          />
        </Form.Item>
      );
    }

    if (type === 2) {
      const inputProps = {
        ...baseProps,
      } as any;
      if (!isEmpty(defaultValue)) {
        inputProps.initialValue = defaultValue;
      }
      if (!isEmpty(value)) {
        inputProps.initialValue = value;
      }

      return !hasFiled ? null : (
        <Form.Item
          className={classnames({ 'hr-form-item-hidden': hiddenFiled, [formItemName]: true })}
          rules={rules}
          {...inputProps}
        >
          <InputItem
            labelNumber={7}
            className="hr-input"
            placeholder="请填写"
            type="text"
            maxLength={verificationLength || undefined}
            disabled={disabled}
            onBlur={(value) => handleValuesChange({ [formItemName]: value })}
            extra={unit}
          >
            {required && <span className="require-icon">*</span>}
            {name}
          </InputItem>
        </Form.Item>
      );
    }

    // 开始时间 date yyyy-mm-dd
    if (type === 14 || type === 10 || type === 11) {
      const datePickerProps = {
        ...baseProps,
      } as any;
      // 兼容后端接口返回时间戳为负数的字符串
      // const timeDate = (!isNaN(value)&&Number(value)<0)?Number(value):value;
      const timeDate = (!isNaN(value)&&(Number(value)<0||value.toString().length>8))?Number(value):value;
      datePickerProps.initialValue = (!isEmpty(value)) ? timeDate : defaultValue;

      return !hasFiled ? null : (
        <Form.Item
          className={classnames({ 'hr-form-item-hidden': hiddenFiled, [formItemName]: true })}
          {...datePickerProps}
          rules={[
            { required, message: `请选择${segmentItem.name}` },
            {
              validator: (_rule, value) => {
                if (type === 10) {
                  const endValue = transformDate(form.getFieldValue(nextSegmentItem.formItemName));
                  if (!value || !endValue) return Promise.resolve();
                  const flag =
                    dayjs(transformDate(value)).isBefore(dayjs(endValue)) ||
                    dayjs(transformDate(value)).isSame(dayjs(endValue));
                  if (!flag) return Promise.reject(`${name}必须小于等于${nextSegmentItem.name}`);
                } else if (type === 11) {
                  const startValue = transformDate(form.getFieldValue(preSegmentItem.formItemName));
                  const flag =
                    dayjs(transformDate(value)).isAfter(dayjs(startValue)) ||
                    dayjs(transformDate(value)).isSame(dayjs(startValue));
                  if (!value || !startValue) return Promise.resolve();
                  if (!flag) return Promise.reject(`${name}必须大于等于${preSegmentItem.name}`);
                }

                return Promise.resolve();
              },
            },
          ]}
        >
          <DatePicker
            disabled={disabled}
            mode={mode}
            format={format}
            title={name}
            minDate={new Date(1900, 0, 1, 0, 0, 0)}
            maxDate={new Date(2100, 11, 31, 23, 59, 59)}
            required={required}
          />
        </Form.Item>
      );
    }

    // picker 下拉
    if (type === 1 || type === 3 || type === 8 || type === 9) {
      const pickerProps = {
        ...baseProps,
      } as any;
      pickerProps.initialValue = !isEmpty(value) ? value : defaultValue;
      // 字典项下拉是字符串
      if (!isEmpty(pickerProps.initialValue) && !Array.isArray(pickerProps.initialValue)) {
        pickerProps.initialValue = pickerProps.initialValue.toString();
      }
      let cols = 1;
      let valueKey = 'id'
      if (type === 8) {
        cols = 2;
      } else if (type === 9) {
        cols = 3;
        valueKey = 'areaId'
      }

      return !hasFiled ? null : (
        <Form.Item
          className={classnames({ 'hr-form-item-hidden': hiddenFiled, [formItemName]: true })}
          {...pickerProps}
          rules={[{ required, message: `请选择${segmentItem.name}` }]}
        >
          <Picker
            data={
              dictionaryList
                ? dictionaryList.map((item) => ({
                    label: item.label || item.dataValue,
                    value: item.value || item.dataKey,
                  }))
                : []
            }
            fetchData={(current, selected, value) =>
              typeof getData === 'function'
                ? getData(segmentItem, { current, selected, value })
                : () => []
            }
            url={sourceUrl ? `${apiPrefix}${sourceUrl}` : ''}
            dataFormat={newDataFormat}
            labelKey="name"
            valueKey={valueKey}
            cols={cols}
            cache
            textFormat={
              typeof textFormat === 'function'
                ? (data) => handleTextFormat(segmentItem, data)
                : undefined
            }
            requestOptions={newRequestOptions}
            title={name}
            disabled={disabled}
            onChange={(value, label, item) => {
              handleValuesChange({ [formItemName]: value }, { label, item });
            }}
          >
            <List.Item arrow="down">
              {required && <span className="require-icon">*</span>}
              {name}
            </List.Item>
          </Picker>
        </Form.Item>
      );
    }

    // 上传图片
    if (type === 5 || displayWay === 0) {
      const uploadProps = {
        ...baseProps,
        valuePropName: 'fileList',
        rules: [
          { validator: (_, value) => validIdUpload(value, required, `请上传${segmentItem.name}`) },
        ],
      } as any;
      let options = {
        url: '',
        data: {},
      } as any;
      if (typeof requestOptions === 'function') {
        options = requestOptions(segmentItem);
      }
      // 这里到时候要处理下file类型的转换
      if (Array.isArray(segmentItem.value)) {
        uploadProps.initialValue = segmentItem.value.map((item) => ({
          ...item,
          uid: item.id,
          status: 'done',
          url: filePathPrefix
            ? filePathPrefix + (item.url || item.materialsPic)
            : item.url || item.materialsPic,
        }));
      }
      return !hasFiled ? null : (
        <Form.Item
          className={classnames({ 'hr-form-item-hidden': hiddenFiled, [formItemName]: true })}
          {...uploadProps}
        >
          <UploadWrapper
            title={
              <div>
                {required && <span className="require-icon">*</span>}
                {segmentItem.name}
              </div>
            }
          >
            <Upload
              max={options.max}
              url={options.url}
              data={options.data}
              formItemName={baseProps.name}
              type="icon-card"
              multiple={options.multiple}
              disabled={disabled}
              canDelete={options.canDelete}
              beforeRemove={beforeRemove}
              onRespone={onRespone}
              onFinsh={(files) => handleValuesChange({ [formItemName]: files })}
            />
          </UploadWrapper>
        </Form.Item>
      );
    }

    // 通讯录/城市（索引A，B，C...）列表 indexList
    if (type === 6) {
      const indexListProps = {
        ...baseProps,
      } as any;
      if (segmentItem.value !== undefined && segmentItem.value !== null) {
        indexListProps.initialValue = segmentItem.value;
      }
      return !hasFiled ? null : (
        <Form.Item
          className={classnames({ 'hr-form-item-hidden': hiddenFiled, [formItemName]: true })}
          {...indexListProps}
          rules={[{ required, message: `请选择${segmentItem.name}` }]}
        >
          <IndexList
            data={dictionaryList}
            cache
            title={name}
            required={required}
            url={segmentItem.url ? segmentItem.url : null}
            onChange={(value) => handleValuesChange({ [formItemName]: value })}
          />
        </Form.Item>
      );
    }

    if (type === 12) {
      const levelSelectItemProps = {
        ...baseProps,
      } as any;
      if (segmentItem.value !== undefined && segmentItem.value !== null) {
        levelSelectItemProps.initialValue = segmentItem.value;
        // 字典项下拉是字符串
        if (!isEmpty(levelSelectItemProps.initialValue) && !Array.isArray(levelSelectItemProps.initialValue)) {
          levelSelectItemProps.initialValue = []// levelSelectItemProps.initialValue.toString();
        }
      }
      return (
        <Form.Item
          className={classnames({ 'hr-form-item-hidden': hiddenFiled, [formItemName]: true })}
          {...levelSelectItemProps}
          rules={[{ required, message: `请选择${segmentItem.name}` }]}
        >
          <LevelSelectItem
            title={name}
            required={required}
            // eslint-disable-next-line @typescript-eslint/no-shadow
            fetchData={(current, selected, value) =>
              typeof getData === 'function'
                ? getData(segmentItem, { current, selected, value })
                : () => []
            }
            textFormat={
              typeof textFormat === 'function'
                ? (data) => handleTextFormat(segmentItem, data)
                : undefined
            }
          />
        </Form.Item>
      );
    }


    if (type === 13) {
      const searchItemProps = {
        ...baseProps,
      } as any;
      if (segmentItem.value !== undefined && segmentItem.value !== null) {
        searchItemProps.initialValue = segmentItem.value;
      }
      return (
        <Form.Item
          className={classnames({ 'hr-form-item-hidden': hiddenFiled, [formItemName]: true })}
          {...searchItemProps}
          rules={[{ required, message: `请选择${segmentItem.name}` }]}
        >
          <SearchItem
            title={name}
            getData={(pageIndex, pageSize, payload) =>
              typeof getData === 'function'
                ? getData(segmentItem, { pageIndex, pageSize, payload })
                : () => []
            }
            renderRow={
              typeof renderItem === 'function'
                ? (rowData) => renderItem(segmentItem, rowData)
                : undefined
            }
            formatText={
              typeof textFormat === 'function'
                ? (data) => handleTextFormat(segmentItem, data)
                : undefined
            }
          />
        </Form.Item>
      );
    }

    return null;
  };

  const renderFooter = (item) => {
    if (typeof footer === 'function') {
      return () => footer(item);
    }
    return null;
  };
  const handleClick = (data) => {
    if (typeof onClick === 'function') {
      onClick(data);
    }
  };

  const renderSegments = (segments) => {
    return segments.map((segmentItem, segmentsIndex) => {
      if (Array.isArray(segmentItem)) {
        return segmentItem.map((singleSegmentItem, singleSegmentItemIndex) => (
          <List key={singleSegmentItem.code}>
            <div className="hr-list-body-wrapper">
              {renderFormItem(
                singleSegmentItem,
                segmentItem[singleSegmentItemIndex + 1],
                segmentItem[singleSegmentItemIndex - 1],
              )}
            </div>
          </List>
        ));
      }
      return (
        <List className="my-list" key={segmentItem.name}>
          <div onClick={() => handleClick(segmentItem)}>
            {renderFormItem(segmentItem, segments[segmentsIndex + 1], segments[segmentsIndex + -1])}
          </div>
        </List>
      );
    });
  };
  return (
    <div className="hr-forms">
      <Form form={form} name="baseform" {...otherProps}>
        {sections.map((item) => {
          const { name, segments, code, display } = item;
          if (display === 'none') return null;
          return hasCollapsePanel ? (
            <CollapsePanel
              title={
                <div className="hr-form-header">
                  {name}
                  {hasCheckIcon && (
                    <Icon
                      className={classnames('hr-form-check', { actived: pass[code] === true })}
                      type="iconqueren"
                    />
                  )}
                </div>
              }
              key={code}
              className="hr-form-collapsep-panel"
              footer={renderFooter(item)}
            >
              {renderSegments(segments)}
              {children}
            </CollapsePanel>
          ) : (
            <div className="hr-no-collapse-panel" key={code}>
              {renderSegments(segments)}
              {children}
            </div>
          );
        })}
      </Form>
    </div>
  );
});

Index.defaultProps = {
  sections: [],
  hasCheckIcon: false,
  hasCollapsePanel: true,
  apiPrefix: '/api',
};

export { fillFramesValue } from './util';
export default Index;

const UploadWrapper: React.FunctionComponent<any> = ({ title, children, id, ...props }) => {
  return (
    <div className="hr-upload-collapse" id={id}>
      <CollapsePanel title={title} controlled>
        {React.cloneElement(children as any, { ...props })}
      </CollapsePanel>
    </div>
  );
};
